﻿// owner 蒋家伟

#pragma once
#include <type_traits>
#include <StringUtils.h>

namespace jsdk
{
    class TemplateCommonUtils
    {
    public:
        // 获取退化后的原始类型
        template<typename T>
        struct Decay
        {
            using type = typename std::remove_pointer_t<std::decay_t<T>>;
        };

        template <typename T>
        using Decay_t = typename Decay<T>::type;

        // 获取classID
        template<typename T>
        static const char* getClassId()
        {
            return typeid(T).name();
        }

        // 判断一个类型是否是模版
        template<typename T>
        struct is_template_class : std::false_type {};

        template<template<typename...> typename T, typename... Ts>
        struct is_template_class<T<Ts...>> : std::true_type {};


        // 判断一个类别是否存在swap方法，swap方法表示与类别相同的对象进行交换
        // 例如std的容器类别都会存在swap方法
        template<typename T>
        struct has_swap_fun
        {
            template<typename U, void(U::*)(U&) = &U::swap>
            static constexpr int check(U*);
            static constexpr char check(...);
            static constexpr bool value = sizeof(check(static_cast<T*>(nullptr))) == sizeof(int);
        };
    };

#pragma region 模版值类型萃取
    // 模版值类型萃取，自定义的模版方法如果重新定义valueType作为模版的T，则可以递归提取valueType最终类型，直到没有valueType定义为止
    // 例子: 
    // template<typename T> struct TestA{using valueType = T;}
    // template<typename T> struct TestB{using valueType = T;}
    // template<typename T> struct TestC{using valueType = T;}
    // template_valuetype_traits<TestA<TestB<TestC<int>>>>::type ->int类型。
    // note : 使用宏进行封装，但是类型名称没有改变，VALUE_TYPE_DEFINE 表示 是如何定义的using valueType = T或者using Type = T 等等，给予了一定的拓展，但这会使得此宏容易引发重复定义的问题。因此需要放在cpp文件中定义一次即可
#define TEMPLATE_VALUETYPE_TRAITS_DEFINE(VALUE_TYPE_DEFINE) \
    CPP_FILE_CHECK\
    template<typename T>\
    struct has_value_type_define\
    {\
        template<typename U>\
        static int check(typename U::VALUE_TYPE_DEFINE *) {};\
        template<typename U>\
        static char check(...) {};\
        static constexpr bool value = (sizeof(check<T>(0)) == sizeof(int));\
    };\
    template<typename T, bool value = has_value_type_define<T>::value>\
    struct template_valuetype_traits : public template_valuetype_traits<typename T :: VALUE_TYPE_DEFINE>\
    {\
        using type = typename template_valuetype_traits<typename T :: VALUE_TYPE_DEFINE>::type;\
    };\
    template<typename T>\
    struct template_valuetype_traits<T, false>\
    {\
        using type = T;\
    };

#pragma region 模版值类型萃取

#pragma region 模版函数偏特化所需的默认参数

    template<bool value, typename = std::enable_if_t<value>>
    struct is_class_type
    {
    };

    template<>
    struct is_class_type<true>
    {
    };

#define IS_CLASS_TYPE(CONDITION) is_class_type< CONDITION >* = nullptr
#pragma region 模版函数偏特化所需的默认参数
}

